package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.api.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.ArticleConstants;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ApArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.NewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Author bo.li
 * @Date 2023/3/17 10:49
 * @Version 1.0
 */
@Service
@Slf4j
public class NewsAutoScanServiceImpl implements NewsAutoScanService {
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private WmNewsMapper newsMapper;
    @Autowired
    private GreenImageScan imageScan;
    @Autowired
    private FileStorageService storageService;
    @Autowired
    private IArticleClient articleClient;
    @Autowired
    private WmChannelMapper channelMapper;
    @Autowired
    private WmUserMapper userMapper;

    @Autowired
    private WmSensitiveMapper sensitiveMapper;
    @Autowired
    private Tess4jClient tess4jClient;
    @Autowired
    private KafkaTemplate kafkaTemplate;


    @Async("asyncExecutor")
    @Override
//    @GlobalTransactional
    public void newsScan(WmNews wmNews) {
        log.info("开始执行内容安全检测");
        if(wmNews.getStatus() != WmNews.Status.SUBMIT.getCode()){
            log.info("文章状态不是提交，不做审核");
            return;
        }
        //提取文章内容和图片
        Map<String, Object> contentAndPics = getContentAndPics(wmNews);
        //自定义敏感词审核
        boolean flag = handleSensitive(wmNews,contentAndPics.get("content") + "");
        if(!flag){
            log.info("文本中存在敏感词，不走后续流程");
            return;
        }

        //文本审核
        flag = scanText(wmNews, contentAndPics.get("content") + "");
        if(!flag){
            log.info("文本中存在违规内容,不再执行后续流程");
            return;
        }
        //图片审核
        flag = scanImages(wmNews,(List<String>) contentAndPics.get("images"));
        if(!flag){
            log.info("图片中存在违规内容,不再执行后续流程");
            return;
        }
        //保存到APP端
        ResponseResult result = saveToApp(wmNews);
        log.info("保存APP返回结果：{}",JSON.toJSONString(result));

        if(result.getCode() == AppHttpCodeEnum.SUCCESS.getCode()){
            //更新数据库
            wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
            wmNews.setArticleId((long)result.getData());
            newsMapper.updateById(wmNews);

            //发送消息通知
            kafkaTemplate.send(ArticleConstants.TOPIC_CREATE_DETAIL_HTML,result.getData() + "");
        }
        log.info("文章:{}审核完成",wmNews.getId());
    }

    /***
     * 自定义敏感词审核
     * @param wmNews
     * @param content
     * @return
     */
    private boolean handleSensitive(WmNews wmNews, String content) {
        boolean flag = true;
        //查询所有敏感词
        List<WmSensitive> wmSensitives = sensitiveMapper.selectList(Wrappers.emptyWrapper());
        if(CollectionUtils.isEmpty(wmSensitives)){
            log.info("未定义敏感词，不做审核");
            return flag;
        }
        List<String> sensitiveWords = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        SensitiveWordUtil.initMap(sensitiveWords);
        Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(content);
        if(!CollectionUtils.isEmpty(resultMap)){
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason(resultMap.toString());
            flag = false;
            newsMapper.updateById(wmNews);
        }

        return flag;
    }

    /**
     * 保存文章到APP
     * @param wmNews
     * @return
     */
    private ResponseResult saveToApp(WmNews wmNews) {
        ApArticleDto articleDto = new ApArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        articleDto.setLayout(wmNews.getType());
        WmChannel channel = channelMapper.selectById(wmNews.getChannelId());
        articleDto.setChannelName(channel == null ? null : channel.getName());
        WmUser user = userMapper.selectById(wmNews.getUserId());
        articleDto.setAuthorName(user == null ? null : user.getNickname());
        articleDto.setAuthorId(wmNews.getUserId());
        //修改
        if(wmNews.getArticleId() != null){
            articleDto.setId(wmNews.getArticleId());
        }

        ResponseResult result = articleClient.saveArticle(articleDto);
        return result;
    }

    /**
     * 图片审核
     *
     * @param wmNews
     * @param pics
     * @return
     */
    private boolean scanImages(WmNews wmNews , List<String> pics){
        boolean flag = true;
        if(CollectionUtils.isEmpty(pics)){
            return flag;
        }
        try {
            pics = pics.stream().distinct().collect(Collectors.toList());
            List<byte[]> images = new ArrayList<>();
            for (String pic : pics) {
                byte[] imageBtyes = storageService.downLoadFile(pic);
                //敏感词审核
                BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBtyes));
                String picContent = tess4jClient.doOCR(bufferedImage);
                flag = handleSensitive(wmNews, picContent);
                if(!flag){
                    log.info("图片中含有敏感词，不再执行后续流程");
                    return flag;
                }
                images.add(imageBtyes);
            }

            Map result = imageScan.imageScan(images);
            flag = dealResult(result,wmNews);
        }catch (Exception e){
            log.error("图片审核异常",e);
            flag = false;
        }

        return flag;
    }

    /**
     *
     * 结果处理
     * @param result
     * @param wmNews
     * @return
     */
    private boolean dealResult(Map result,WmNews wmNews){
        boolean flag = true;
        if(result == null){
            return flag;
        }
        String suggestion = result.get("suggestion") + "";
        String label = result.get("label") + "";
        if("pass".equals(suggestion)){
            return flag;
        }
        //处理失败和人工
        flag = false;
        if("block".equals(suggestion)){
            //更新数据库
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("文本或者图片中包含违法内容：" + label);
        }else if("review".equals(suggestion)){
            //更新数据库
            wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
            wmNews.setReason("文本或图片中包含不确定内容：" + label);
        }
        newsMapper.updateById(wmNews);
        return flag;
    }

    /**
     *
     *
     * @param wmNews
     * @param content
     * @return
     */
    private boolean scanText(WmNews wmNews,String content){
        boolean flag = true;
        try {
            Map result = greenTextScan.greeTextScan(content);
            log.info("文本审核结果：{}",result);
            flag = dealResult(result,wmNews);
        }catch (Exception e){
            log.error("文本扫描失败",e);
            return false;
        }
        return flag;
    }

    /**
     * 提取文章图片和内容
     * @param wmNews
     * @return
     */
    private  Map<String, Object> getContentAndPics(WmNews wmNews){
        Map<String,Object> result = new HashMap<>();
        List<String> pics = new ArrayList<>();
        StringBuilder content = new StringBuilder();
        //{"type":"text","value":"aabf"}
        List<Map> mapList = JSON.parseArray(wmNews.getContent(), Map.class);
        for (Map map : mapList) {
            if("image".equals(map.get("type"))){
                pics.add(map.get("value") + "");
            }else if("text".equals(map.get("type"))){
                content.append(map.get("value") + "");
            }
        }
        //添加标题
        content.append("-").append(wmNews.getTitle());

        //封面图片  a,b,d ->[a,b,c]
        if(!StringUtils.isEmpty(wmNews.getImages())){
            pics.addAll(StringUtils.commaDelimitedListToSet(wmNews.getImages()));
        }
        result.put("content",content.toString());
        result.put("images",pics);
        return result;
    }
}